/*
mqtt.c
mqtt realizy pulisher and subscribe message
designed by lunanting

-------------------------
2020-05-14 12:00:10
create file
-------------------------
*/
#include <stdlib.h>
#include "linkkit/infra/infra_types.h"
#include "linkkit/infra/infra_defs.h"
#include "linkkit/infra/infra_compat.h"
#include "linkkit/dev_model_api.h"
#include "linkkit/infra/infra_config.h"
#include "linkkit/wrappers/wrappers.h"
#include "mqtt.h"
#include "string.h"
#include "stdio.h"
#include "bsp.h"
#include "aos/kernel.h"
#include "aos/yloop.h"
#include "aos/hal/uart.h"
#include "../../../../utility/cjson/include/cJSON.h"
#include "xp_time.h"
#ifdef WITH_LWIP

#else
#include <atcmd_config_module.h>
#endif
#include "aos/kv.h"
#if defined(ENABLE_AOS_OTA)
#include "ota/ota_service.h"
int ota_thread_create(void **thread_handle, void *(*work_routine)(void *), void *arg, void *pm, int stack_size);
#endif

static MQTT_class *mqtt;
static void (*user_deal_api)(const char *key,const char *value)=NULL;


static char product_key[]="a1XnYvV1YBk";
static char product_secret[]="qOJ3N6NGRjFnK7fT";
static char device_name[]="demo";
static char device_secret[]="746c2eb38f3ff30a3e19306fbaba833e";



void xp_mqtt_init_regster(void);



void xp_4g_connect_event(input_event_t *event, void *priv_data);

void mqtt_ntp_request(void)
{
    char topic[100];
    char data[100];
    sprintf(topic, "/ext/ntp/%s/%s/request", mqtt->target.product_key, mqtt->target.device_name);
    sprintf(data, "{\"deviceSendTime\":\"%lld\"}", xp_time_get_ms());
    int ret = IOT_MQTT_Publish_Simple(0, topic, IOTX_MQTT_QOS0, data, strlen(data));
    println("topic: %s, data: %s %d", topic, data, ret);
}

/*
mqtt thread
*/
void xp_mqtt_thread(void *arg){
    int domain_type=0,dynamic_register=0,post_event_reply = 0;
    MQTT_class *mq=(MQTT_class *)arg;
    int count=0;
    if(mq==NULL){
        aos_task_exit(0);
    }
    xp_mqtt_config(mq);
    while(1){
        IOT_Linkkit_Yield(200);
        count=0;
        if(xp_mqtt_link_available(mq)!=1){
            count++;
            println("Network disconnect,online= %d, connect= %d; offline time= %d s;will try reconnect !",mq->online,mq->connect,count);
            #ifndef WITH_LWIP
            void sal_reconnect(void *arg);
            sal_reconnect(NULL);
            #endif
            IOT_Linkkit_Close(mq->devid);
            xp_mqtt_open(mq);
            if(xp_mqtt_connect(mq)==0){
                mq->connect=1;
                mq->online=1;
                count=0;
            }
            else{
                #ifdef WITH_LWIP

                #else
                // void sal_reconnect(void *arg);
                // sal_reconnect(&st_sal_dev_conf);
                // println("mqtt reconnect socket !");
                // aos_msleep(500);
                // domain_type=IOTX_CLOUD_REGION_SHANGHAI;
                // IOT_Ioctl(IOTX_IOCTL_SET_DOMAIN,(void *)&domain_type);
                // /* Choose Login Method */
                // dynamic_register = 0;
                // IOT_Ioctl(IOTX_IOCTL_SET_DYNAMIC_REGISTER, (void *)&dynamic_register);
                // /* Choose Whether You Need Post Property/Event Reply */
                // int post_event_reply = 0;
                // IOT_Ioctl(IOTX_IOCTL_RECV_EVENT_REPLY, (void *)&post_event_reply);
                // xp_mqtt_open(mq);
                // xp_mqtt_connect(mq);
                #endif
            }
        }

        aos_msleep(1000);
    }

}

/*
loop thread
*/
void xp_mqtt_loop_thread(void *arg){
    int count=0;
    char value[100]={0};
    int len=100;
    int sta=0;
    MQTT_class *mq=(MQTT_class *)arg;
    
    if(mq==NULL){
        while(1){
ERR:        
            if(sta==0){
                perr("mqtt obj == NULL,init fail~");
            }
            else if(sta<=-1){
                //perr("mqtt get kv key error: code = %d",sta);
            }
            aos_msleep(2000);
        }
    }

    strcpy(mq->target.device_name,device_name);
    strcpy(mq->target.device_secret,device_secret);
    strcpy(mq->target.product_key,product_key);
    strcpy(mq->target.product_secret,product_secret);

    memset(value,0,strlen(value));
    if(aos_kv_get("device_name",value,&len)==0){
        if(strlen(value)>5){
            println("kv loader device_key:%s",value);
            strcpy(mq->target.device_name,value);
        }
        else{
            sta=-1;
            goto ERR;
        }
    }
    else{
        sta=-1;
        goto ERR;
    }
    len=100;
    memset(value,0,strlen(value));
    if(aos_kv_get("device_secret",value,&len)==0){
        if(strlen(value)>5){
            println("kv loader device_secret:%s",value);
            strcpy(mq->target.device_secret,value);
        }
    }
    else{
        sta=-2;
        goto ERR;
    }
    len=100;
    memset(value,0,strlen(value));
    if(aos_kv_get("product_key",value,&len)==0){
        if(strlen(value)>5){
            println("kv loader product_key:%s",value);
            strcpy(mq->target.product_key,value);
        }
    }
    else{
        sta=-3;
        goto ERR;
    }
    len=100;
    memset(value,0,strlen(value));
    if(aos_kv_get("product_secret",value,&len)==0){
        if(strlen(value)>5){
            println("kv loader product_secret:%s",value);
            strcpy(mq->target.product_secret,value);
        }
    }
    else{
        sta=-4;
        goto ERR;
    }
    #ifdef WITH_LWIP
    aos_msleep(1500);
    #else
    println("wait for 4G module ready.....");
    aos_msleep(15000);
    #endif
    aos_task_new("mqtt thread",xp_mqtt_thread,mq,1024*8);
    aos_loop_run();
    while(mq->init!=1){
        count++;
        if(count>50){
            while(1){
                println("Connect ali IOT fail~");
                aos_msleep(2000);
            }
        }
        aos_msleep(1000);
    }
    println("Connect ali IOT success~");
    
}


/*
mqtt init
*/
int xp_mqtt_init(MQTT_class *mq){

    if(mq==NULL){
        perr("mqtt obj == NULL,init fail~");
        return -1;
    }
    
    aos_task_new("mqtt loop thread",xp_mqtt_loop_thread,mq,1024*4);
    return 0;
}
void iotx_mqtt_event_handle_func_cb(void *pcontext, void *pclient, iotx_mqtt_event_msg_pt msg)
{
    iotx_mqtt_topic_info_pt p = (iotx_mqtt_topic_info_pt)msg->msg;
    println("NTP %s", (char *)p->payload);
    cJSON* pRecRoot = cJSON_Parse(p->payload);
    cJSON* item = cJSON_GetObjectItem(pRecRoot, 0);
    if(!cJSON_IsNull(item)){
        int size = cJSON_GetArraySize(pRecRoot);
        for (size_t i = 0; i < size; i++)
        {
            item = cJSON_GetArrayItem(pRecRoot, i);
            if(!cJSON_IsNull(item) && 0 == strcmp(item->string, "serverSendTime")){
                uint64_t num;
                if(1 == sscanf(item->valuestring, "%llu", &num)){
                    println("Time value ms %lld", num);
                    xp_rtc_set_with_unix(num/1000);
                }
            }
        }
    }
    cJSON_Delete(pRecRoot);
}


/*
mqtt  init
param:

return:
    0=success
*/
int xp_mqtt_config(MQTT_class *mq){
    int domain_type=0,dynamic_register=0,post_reply_need=0,fota_timeout=30;
    iotx_linkkit_dev_meta_info_t *info=&mq->info;
    int sta=0,count=0;
    if(mq==NULL){
        mqtt=NULL;
        return -1;
    }
    mqtt=mq;
    // IOT_SetLogLevel(IOT_LOG_DEBUG);
    xp_mqtt_set_target(&mq->target);
    xp_mqtt_init_regster();
    memset(info,0,sizeof(iotx_linkkit_dev_meta_info_t));
    HAL_GetProductKey(info->product_key);
    HAL_GetDeviceName(info->device_name);
    HAL_GetProductSecret(info->product_secret);
    HAL_GetDeviceSecret(info->device_secret);

    #ifdef WITH_LWIP

    #else
    //启动4G模块
    sal_device_config_t  st_sal_dev_conf = {0};
    aos_register_event_filter(EV_WIFI, xp_4g_connect_event, NULL);
    extern uart_dev_t uart_4G;
    memcpy(&(st_sal_dev_conf.uart_dev), &uart_4G, sizeof(uart_dev_t));
    sal_add_dev(NULL, &st_sal_dev_conf);
    sal_init();
    while(mqtt->online!=1){
        count++;
        if((count%150)==0){
            perr("4G can not connect network,over %d seconds.",count/10);
            // aos_reboot();
            println("4G module network fail !!");
            break;
        }
        aos_msleep(100);
    }
    println("4G module network online!!");
    #endif
    /* Choose Login Server, domain should be configured before IOT_Linkkit_Open() */
    domain_type=IOTX_CLOUD_REGION_SHANGHAI;
    IOT_Ioctl(IOTX_IOCTL_SET_DOMAIN,(void *)&domain_type);
    /* Choose Login Method */
    dynamic_register = 0;
    IOT_Ioctl(IOTX_IOCTL_SET_DYNAMIC_REGISTER, (void *)&dynamic_register);
    /* Choose Whether You Need Post Property/Event Reply */
    int post_event_reply = 0;
    IOT_Ioctl(IOTX_IOCTL_RECV_EVENT_REPLY, (void *)&post_event_reply);
    /* Create Master Device Resources */
    if(xp_mqtt_open(mq)<0){
        sta=-1;
        aos_msleep(2000);
    }
    /* Start Connect Aliyun Server */
    if(xp_mqtt_connect(mq)<0){
        sta=-2;
        aos_msleep(2000);
    }
    char sub_topic[100];
    sprintf(sub_topic, "/ext/ntp/%s/%s/response", mq->target.product_key, mq->target.device_name);
    IOT_MQTT_Subscribe(NULL, sub_topic, IOTX_MQTT_QOS0, iotx_mqtt_event_handle_func_cb, NULL);
    println("sub_topic: %s", sub_topic);
    mqtt_ntp_request();
    sta=0;
	mq->init=1;
    if(sta!=0){
        println("MQTT int fail~~");
        return sta;
    }
    println("MQTT init success!");
    return 0;
}


/*
set mqtt target
param:
    target:target message
return:
    0=success
*/
int xp_mqtt_set_target(MQTT_target *target){
    if(target==NULL)return -1;
    HAL_SetProductKey(target->product_key);
    HAL_SetProductSecret(target->product_secret);
    HAL_SetDeviceName(target->device_name);
    HAL_SetDeviceSecret(target->device_secret);
}

#if defined(ENABLE_AOS_OTA)
/*
return server 
*/
static ota_service_t ps;
ota_service_t *xp_mqtt_server_get(void)
{
    char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0};
    char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0};
    char device_secret[IOTX_DEVICE_SECRET_LEN + 1] = {0};
    char product_secret[IOTX_PRODUCT_SECRET_LEN + 1] = {0};
    HAL_GetProductSecret(product_secret);
    HAL_GetProductKey(product_key);
    HAL_GetDeviceName(device_name);
    HAL_GetDeviceSecret(device_secret);

    strncpy(ps.pk, product_key, sizeof(ps.pk) - 1);
    strncpy(ps.dn, device_name, sizeof(ps.dn) - 1);
    strncpy(ps.ds, device_secret, sizeof(ps.ds) - 1);
    strncpy(ps.ps, product_secret, sizeof(ps.ps) - 1);
    return &ps;
}
#endif

/*
open a mqtt 
param:
    mq:mqtt object
return:
    0=success
*/
int xp_mqtt_open(MQTT_class *mq){
    if(mq==NULL)return -1;
    mq->devid= IOT_Linkkit_Open(IOTX_LINKKIT_DEV_TYPE_MASTER,&mq->info);
    if (mqtt->devid < 0) {
        println("mqtt open Fail~");
        return -1;
    }
    return 0;
}

/*
connect a mqtt server
param:
    mq:mqtt object
return:
    0=success
*/
int xp_mqtt_connect(MQTT_class *mq){
    if(mq==NULL)return -1;
    if(IOT_Linkkit_Connect(mq->devid)<0){
        //println("mqtt connect fail~");
        return -1;
    }
    return 0;
}

/*
close a mqtt server
param:
    mq:mqtt object
*/
void xp_mqtt_close(MQTT_class *mq){
    if(mq==NULL)return ;
    IOT_Linkkit_Close(mq->devid);
    IOT_DumpMemoryStats(IOT_LOG_DEBUG);
    IOT_SetLogLevel(IOT_LOG_NONE);
}


/*
mqtt link available state
return:
    1=available
    0=not available
*/
int xp_mqtt_link_available(MQTT_class *mq){
    if(mq==NULL)return -1;
    if(mq->init!=1)return -2;
    if(mq->online!=1)return -3;
    if(mq->connect){
        return 1;
    }
    //println("mqtt link not available!\r\nreconnect mqttt server!");
    return 0;
}

/*
mqtt post data
param:
    mq:mqtt object
    data:data
    len:data length
return:
    >0=message id
    0=success
    -1=fail
*/
int xp_mqtt_post_data(MQTT_class *mq,u8 *data,int len){
    if(mq==NULL)return -1;
    if(xp_mqtt_link_available(mq)!=1)return -2;
    int rec=IOT_Linkkit_Report(mq->devid,ITM_MSG_POST_RAW_DATA,data,len);
    if(rec>=0){
        println("mqtt post data message id=%d",rec);
    }
    else{
        println("mqtt post data fail~");
    }
    return rec;    
}


/*
mqtt post string
param:
    str:post string
return:
    >0=message id
    0=success
    -1=fail    
*/
int xp_mqtt_post_string(MQTT_class *mq,char *str){
    if(mq==NULL)return -1;
    if(xp_mqtt_link_available(mq)!=1)return -2;
    return xp_mqtt_post_data(mq,(u8 *)str,strlen(str));
}

/*
mqtt post property
param:
    mq:mqtt object
    property:property string
return:
    >0=message id
    0=success
    -1=fail    
*/
int xp_mqtt_post_property(MQTT_class *mq,char *property){
    int ret=0;

    if(mq==NULL)return -1;
    ret=xp_mqtt_link_available(mq);
    if(ret!=1){
        perr("mqtt link available return: %d.",ret);
        return -2;
    }
    int rec=IOT_Linkkit_Report(mq->devid,ITM_MSG_POST_PROPERTY,(u8 *)property,strlen(property));
    if(rec>=0){
        println("mqtt post property message id:%d",rec);
    }
    else{
        println("mqtt post property fail~");
    }
    return rec;
}


/*
mqtt post event
param:
    mq:mqtt object
    event_id:event id
    event_value:event value
return:
    >0=message id
    0=success
    -1=fail    
*/
int xp_mqtt_post_event(MQTT_class *mq,char *event_id,char *event_value){
    if(mq==NULL)return -1;
    if(xp_mqtt_link_available(mq)!=1)return -2;
    int rec=IOT_Linkkit_TriggerEvent(mq->devid,event_id,strlen(event_id),event_value,strlen(event_value));
    if(rec>=0){
        println("mqtt post event message id: %d",rec);
    }
    else{
        println("mqtt post event fail~");
    }
    return rec;
}

/**********************************mqtt event handler****************************/
/*
mqtt connect event handler
*/
static int xp_mqtt_connect_event_handler(void){
    println("mqtt server connect!");
    mqtt->connect=1;
    mqtt->online=1;
    return 0;
}

/*
mqtt disconnect event handler
*/
static int xp_mqtt_disconnect_event_handler(void){
    println("mqtt server disconnect!");
    mqtt->connect=0;
    return 0;
}

/*
mqtt recived data evnet handler
*/
static int xp_mqtt_recived_data_event_handler(const int devid,const unsigned char *payload,const int payload_len){
    println("mqtt recide data:device id=%d,data length=%d",devid,payload_len);
    print("   data=%s\r\n",payload_len);
    return 0;
}

/*
mqtt server request event handler
*/
static int xp_mqtt_server_request_event_handler(const int devid,const char *serviceid,const int service_len,
                                                const char *request,const int request_len,
                                                char **response,int *response_len){
    println("mqtt server request:device id=%d,service id=%s",devid,serviceid);
    return 0;
}


/*
mqtt property desired reply event
*/
static int xp_mqtt_property_desired_get_reply_event_handler(const char *request,const int request_len){
    println("server reply:%s",request);
    return 0;
}

/*
mqtt set property event
*/
static int xp_mqtt_property_set_event_handlerr(const int devid,const char *request,const int request_len){
    int rec=0;
    rec=IOT_Linkkit_Report(mqtt->devid,ITM_MSG_POST_PROPERTY,(unsigned char *)request,request_len);
    // println("post property message id:%d",rec);
    xp_mqtt_recive_property_user_api(request);
    if(rec<0)return -1;
    else{
        return 0;
    }
}

/*
mqtt property want delete a trigger
*/
static int xp_mqtt_property_delete_trigger(void){
    const char *request = "[\"PowerSwitch\"]";
    unsigned int request_len = strlen(request);
    println("mqtt want delete send request:%s",request);
    IOT_Linkkit_Report(mqtt->devid,ITM_MSG_PROPERTY_DESIRED_DELETE,(unsigned char *)request,request_len);
    return 0;
}


/*
mqtt property want get a trigger
*/
static int xp_mqtt_property_get_trigger(void){
    const char *request = "[\"PowerSwitch\"]";
    unsigned int request_len = strlen(request);
    println("mqtt send request:%s",request);
    IOT_Linkkit_Report(mqtt->devid,ITM_MSG_PROPERTY_DESIRED_GET,(unsigned char *)request,request_len);
    return 0;
}

/*
mqtt property get event handler
*/
static int xp_mqtt_property_get_event_handler(const int devid,const char *request,const int request_len,
                                            char **response,int *response_len){
    char ps[] = "{\"PowerSwitch\":1}";
    *response=ps;
    *response_len=strlen(*response);
    println("mqtt property get response:%s",response);
    return 0;
}

/*
mqtt report reply event handler
*/
static int xp_report_reply_event_handler(const int devid,const int msgid,const int code,const char *reply,const int reply_len){
    const char *reply_value = (reply == NULL) ? ("NULL") : (reply);
    const int reply_value_len = (reply_len == 0) ? (strlen("NULL")) : (reply_len);

    println("mqtt post reply recived,devid=%d,msgid=%d,code=%d",devid,msgid,code);
    print("   reply:%.*s\r\n",reply_value_len,reply_value);
    return 0;
}


/*
mqtt trigger event reply event
*/
static int xp_mqtt_trigger_event_reply_event_handler(const int devid,const int msgid,const int code,const char *eventid,
                                                    const int eventid_len,const char *message,const int message_len){
    println("mqtt trigger event reply recived,devid=%d,mgsid=%d,code=%d,eventid=%s",devid,
                                                                                    msgid,
                                                                                    code,
                                                                                    eventid);
    print("    message:%s\r\n",message);
    return 0;
}


/*
mqtt init success
*/
static int xp_mqtt_inited(const int devid){
    println("device init success,devid=%d",devid);
    if(devid==mqtt->devid){
        mqtt->init=1;
    }
    return 0;
}

/*
mqtt cota event handler
*/
static int xp_mqtt_cota_event_handler(int type,const char *config_id,int config_size,const char *get_type,
                                        const char *sign,const char *sign_method,const char *url){
    char buffer[128] = {0};
    int buffer_length = 128;

    println("new config id: %s",config_id);
    println("new config size: %d",config_size);
    println("new config type: %s",get_type);
    println("new config sign: %s",sign);
    println("new config sign method: %s",sign_method);
    println("new config url: %s",url);
    IOT_Linkkit_Query(mqtt->devid,ITM_MSG_QUERY_COTA_DATA,(unsigned char *)buffer, buffer_length);
    return 0;
}


#if defined(ENABLE_AOS_OTA)
/*
repack start entry
*/
int xp_ota_start(ota_service_t *ctx){
    // xp_wdg_stop();
    return ota_service_start(ctx);
}



extern bool is_device_allow_OTA(void);
extern void OTA_start_stop_service(void);
/*
ota upgrade callback

*/
static int ota_upgrade_cb(char* ver, char* url){
    int ret=0;
    void *thread = NULL;

    println("ota version:%s is coming, if OTA upgrade or not ?\n", ver);
    uint16_t timeOutCnt = 0;
    while (timeOutCnt++ < 200 && !is_device_allow_OTA())
    {
        println("Wait device wash service finish, wait time %d S", 3*timeOutCnt);
        aos_msleep(3000);
    }
    OTA_start_stop_service();
    ret = ota_thread_create(&thread, (void *)xp_ota_start, (void *)&ps, NULL, 1024 * 6);
    if(ret<0){
        perr("ota thread error : return = %d.",ret);
    }
    return ret;
}
#endif

/*
ota init handler
*/
static int xp_connect_event_handler(void){
    #if defined(ENABLE_AOS_OTA)
    println("OTA service init ...\n");
    ota_service_init(xp_mqtt_server_get());
    ota_register_cb(OTA_CB_ID_UPGRADE, (void*)ota_upgrade_cb);
    #endif
}


/*
mqtt register callback
*/
void xp_mqtt_init_regster(void){
    IOT_RegisterCallback(ITE_CONNECT_SUCC,xp_mqtt_connect_event_handler);
    IOT_RegisterCallback(ITE_DISCONNECTED,xp_mqtt_disconnect_event_handler);
    IOT_RegisterCallback(ITE_RAWDATA_ARRIVED,xp_mqtt_recived_data_event_handler);
    IOT_RegisterCallback(ITE_SERVICE_REQUEST,xp_mqtt_server_request_event_handler);
    IOT_RegisterCallback(ITE_PROPERTY_SET,xp_mqtt_property_set_event_handlerr);
    IOT_RegisterCallback(ITE_PROPERTY_GET,xp_mqtt_property_get_event_handler);
    IOT_RegisterCallback(ITE_REPORT_REPLY,xp_report_reply_event_handler);
    IOT_RegisterCallback(ITE_TRIGGER_EVENT_REPLY,xp_mqtt_trigger_event_reply_event_handler);
    IOT_RegisterCallback(ITE_INITIALIZE_COMPLETED,xp_mqtt_inited);
    IOT_RegisterCallback(ITE_COTA,xp_mqtt_cota_event_handler);
    IOT_RegisterCallback(ITE_MQTT_CONNECT_SUCC, xp_connect_event_handler);
    // IOT_RegisterCallback(ITE_PROPERTY_DESIRED_GET_REPLY,xp_mqtt_property_desired_get_reply_event_handler);
}


/*
4G connect network event
*/
void xp_4g_connect_event(input_event_t *event, void *priv_data){
    if(event->type!=EV_WIFI)return;
    if(event->code!=CODE_WIFI_ON_GOT_IP)return;
    if(event->code==CODE_WIFI_ON_DISCONNECT){
        mqtt->online=0;
        return;
    }
    if(mqtt->online!=1){
        mqtt->online=1;
    }
}



/*
mqtt recive property set message weak define
param:
    msg:recive message
*/
void __weak xp_mqtt_recive_property_user_api(const char *msg){
    char key[30]={0},value[50]={0},*foot;

    if(msg==NULL)return;

    if(user_deal_api==NULL){
        println("No deal api, property: %s",msg);
    }
    else{
        println("mqtt recive data: %s",msg);
        sscanf(msg,"{\"%[^\"]\":%[^}]}",&key,&value);
        // strtok_r(buf,"{",&foot);
        // key=strtok_r(NULL,":",&foot);
        // value=strtok_r(NULL,",}",&foot);
        user_deal_api(key,value);
    }
}


/*
regist user deal api
*/
void xp_mqtt_regist_userDealApi(void (*api)(const char*,const char *)){
    if(api==NULL){
        perr("api regist fail. input a NULL pointer.");
        return;
    }
    user_deal_api=api;
}


int *IOT_region_type_param(void);
/*
set iot region type
need run behind of mqtt init
param:
    0= default region common obj
    1= 1km complay obj
*/
void xp_mqtt_region_set(MQTT_region type){
    int *type_p=IOT_region_type_param();
    if(type==region_1km_complay){
        *type_p=IOTX_CLOUD_REGION_1KM;
    }
    else if(type == region_singapore){
        *type_p=IOTX_CLOUD_REGION_SINGAPORE;
    }
    else if(type == region_american){
        *type_p=IOTX_CLOUD_REGION_USA_WEST;
    }
    else{
        *type_p=IOTX_CLOUD_REGION_SHANGHAI;
    }
}


/***************************非阿里云物联网平台，标准mqtt 协议连接********************/
#define CHECK_NMQ if(nmq==NULL)return -1

// static int nmqtt_connect=0;
static int Nmqtt_net_status(void){
    int status=0;
    #ifdef WITH_LWIP
    int lwip_net_status(void);
        status=lwip_net_status();
    #else
        int ec20_init_status(void);
        status=ec20_init_status();
    #endif
    return status;
}

static void nmqtt_evnet_cb(void *pcontext, void *pclient, iotx_mqtt_event_msg_pt event){
    Nmqtt_class *nmq=(Nmqtt_class *)pcontext;
    println("nmqtt event (default) callback: type= %d.",event->event_type);
    // println("You can set your self callback by nmqtt_eventCB_set()");
    switch(event->event_type){
        case IOTX_MQTT_EVENT_DISCONNECT:
            nmq->connect_status=0;
            println("NMQTT: 0x%x, mqtt disconnect.",nmq);
            break;
        case IOTX_MQTT_EVENT_RECONNECT:
            nmq->connect_status=1;
            println("NMQTT: 0x%x, mqtt reconnect.",nmq);
            for(int i=0;i<SUB_NUB;i++){
                nmqtt_subcrib_id(nmq,i,nmq->sub[i].topic,NULL);
            }
            break;
        case IOTX_MQTT_EVENT_SUBCRIBE_SUCCESS:
            println("NMQTT: 0x%x, mqtt subcribe success.",nmq);
            break;
        case IOTX_MQTT_EVENT_SUBCRIBE_TIMEOUT:
            println("NMQTT: 0x%x, mqtt subcribe timeout.",nmq);
            break;
        case IOTX_MQTT_EVENT_PUBLISH_SUCCESS:
            println("NMQTT: 0x%x, mqtt publish success.",nmq);
            break;
        case IOTX_MQTT_EVENT_PUBLISH_TIMEOUT:
            println("NMQTT: 0x%x, mqtt publish timeout.",nmq);
            break;
        case IOTX_MQTT_EVENT_BUFFER_OVERFLOW:
            println("NMQTT: 0x%x, mqtt buffer overflow.",nmq);
            break;
        default:
            println("NMQTT other msg no deal...");
            break;

    }

}

static void nmqtt_sub_cb(void *pcontext, void *pclient, iotx_mqtt_event_msg_pt sub){
    Nmqtt_sub *psub=(Nmqtt_sub *)pcontext;
    println("NMQTT  0x%x sub (default) callback:",(Nmqtt_class *)psub->nmq);
    // println("You can set your self callback by nmqtt_subCB_set()");
    // println("topic: %s.\r\nmsg: %.100s ...",psub->topic,((iotx_mqtt_topic_info_pt)(sub->msg))->payload);
    if(psub->cb!=NULL){
        psub->cb(psub,((iotx_mqtt_topic_info_pt)(sub->msg))->payload,((iotx_mqtt_topic_info_pt)(sub->msg))->payload_len);
    }

}

static void nmqtt_loop(void *arg){
    Nmqtt_class *nmq=(Nmqtt_class *)arg;
    while(nmqtt_connect(nmq)==0){
        aos_msleep(1000);
    }
    
    for(int i=0;i<nmq->sub_used;i++){
        nmqtt_subcrib(nmq,nmq->sub[i].topic);
    }
    while (1)
    {
        wrapper_mqtt_yield(nmq->client,5000);
        aos_msleep(1000);
    }
    
}


Nmqtt_class *nmqtt_new(char *host,char *client_id,char *usrname,char *passwd){
    Nmqtt_class *mq=NULL;

    mq=(Nmqtt_class*)malloc(sizeof(Nmqtt_class));
    memset(mq,0,sizeof(Nmqtt_class));

    mq->mqtt.port=1883;
    mq->mqtt.host=host;
    mq->mqtt.client_id=client_id;
    mq->mqtt.username=usrname;
    mq->mqtt.password=passwd;
    mq->mqtt.clean_session=0;
    mq->mqtt.request_timeout_ms=2000;
    mq->mqtt.keepalive_interval_ms=60000;
    mq->mqtt.pub_key=NULL;
    mq->mqtt.write_buf_size=2000;
    mq->mqtt.read_buf_size=2000;
    mq->mqtt.handle_event.h_fp=nmqtt_evnet_cb;
    mq->mqtt.handle_event.pcontext=mq;

    aos_task_new("NMQTT loop",nmqtt_loop,mq,1024*4);
    println("NMQTT new success, obj= 0x%x.",mq);
    return mq;
}

void nmqtt_free(Nmqtt_class *nmq){
    if(nmq==NULL)return;
    free(nmq);
}

/*
阻塞型，最长阻塞 5秒
*/
int nmqtt_connect(Nmqtt_class *nmq){
    int try=0;
    CHECK_NMQ;

    nmq->client=wrapper_mqtt_init(&nmq->mqtt);
    while(1){
        if(Nmqtt_net_status()){
            break;
        }
        println("NMQTT wait net status...");
        try++;
        if(try>5){
            println("NMQTT wait net status fail.");
            nmq->connect_status=0;
            return 0;
        }
        aos_msleep(1000);
    }
    if(wrapper_mqtt_connect(nmq->client)==0){
        nmq->connect_status=1;
        println("NMQTT 0x%x connected.",nmq);
    }
    else{
        nmq->connect_status==0;
        println("NMQTT 0x%x connect fail.,nmq");
    }

    return nmq->connect_status;
}

void nmqtt_eventCB_set(Nmqtt_class *nmq,nmqtt_cb cb){
    CHECK_NMQ;
    nmq->mqtt.handle_event.h_fp=cb;
}

void nmqtt_subCB_sets(Nmqtt_class *nmq,sub_usr_cb cb){
    CHECK_NMQ;
    for(int i=0;i<SUB_NUB;i++){
        nmq->sub[i].cb=cb;
    }
}

/*
id: 0~SUB_NUB default: 0~19
*/
void nmqtt_subCB_set(Nmqtt_class *nmq,int id,sub_usr_cb cb){
    CHECK_NMQ;
    nmq->sub[id].cb=cb;
}


int nmqtt_publish(Nmqtt_class *nmq,const char *topic,const char *msg){
    CHECK_NMQ;
    if(nmq->connect_status==0)return -2;
    nmq->payload.packet_id++;
    nmq->payload.ptopic=topic;
    nmq->payload.topic_len=strlen(topic);
    nmq->payload.payload=msg;
    nmq->payload.payload_len=strlen(msg);
    return wrapper_mqtt_publish(nmq->client,nmq->payload.ptopic,&nmq->payload);
}

int nmqtt_subcrib(Nmqtt_class *nmq,const char *topic){
    CHECK_NMQ;
    int i=0;

    for(i=0;i<SUB_NUB;i++){
        if(nmq->sub[i].topic!=NULL){
            if(i==(SUB_NUB-1)){
                println("NMQTT 0x%x sub fail, topic over buff, topic= %s.",nmq,topic);
                return -4;
            }
            if(strcmp(topic,nmq->sub->topic)==0)break;
            continue;
        }

        nmq->sub[i].topic=topic;
        nmq->sub[i].nmq=nmq;
        // nmq->sub[i].cb=nmqtt_sub_cb;
        nmq->sub_used=i+1;
        break;
    }

    int sta=wrapper_mqtt_subscribe(nmq->client,topic,1,nmqtt_sub_cb,&nmq->sub[i]);
    if(sta>=0){
        // println("NMQTT 0x%x subcribe Success, id= sub[%d].",nmq,i);
        return sta;

    }
    else{
        println("NMQTT 0x%x subcribe Fail, id= sub[%d].",nmq,i);
        return -2;
    }
}


int nmqtt_subcrib_id(Nmqtt_class *nmq,int id,const char *topic,nmqtt_cb cb){
    CHECK_NMQ;
    if(topic==NULL){
        return -3;
    }
    nmq->sub[id].topic=topic;
    nmq->sub[id].nmq=nmq;
    if(cb!=NULL){
        nmq->sub[id].cb=cb;
    }
    for(int i=0;i<SUB_NUB;i++){
        if(nmq->sub[i].topic!=NULL){
            nmq->sub_used++;
        }
    }
    int sta=wrapper_mqtt_subscribe(nmq->client,topic,1,nmqtt_sub_cb,&nmq->sub[id]);
    if(sta>=0){
        // println("NMQTT 0x%x subcribe Success, id= sub[%d].",nmq,id);
        return sta;

    }
    else{
        println("NMQTT 0x%x subcribe Fail, id= sub[%d].",nmq,id);
        return -2;
    }
}




/**************************************mqtt test and debug*******************************/
static MQTT_class test={0};
/*
test mqtt link
*/
void xp_mqtt_test(void){
    strcpy(test.target.product_key,"a1dYm92ZAUG");
    strcpy(test.target.product_secret,"W924R0ZNOi7wRIsj");
    strcpy(test.target.device_name,"00001");
    strcpy(test.target.device_secret,"YNf39f1DqGYubygdHfTKfrTLAIorp2TK");
    
    
}

/*
mqtt debug
*/
int xp_mqtt_debug(char *type,char *fun,char *param){
    char str[50];
    if(strcmp(type,"mqtt")!=0)return 0;
    if(strcmp(fun,"post")==0){
        xp_mqtt_post_string(&test,param);
    }
    else if(strcmp(fun,"post_event")==0){
        xp_mqtt_post_event(&test,"Error","{\"errorcode\":0}");
    }
    else if(strcmp(fun,"post_deviceid")==0){
        sprintf(str,"{\"DeviceID\":\"%s\"}",param);
        xp_mqtt_post_property(&test,str);
    }
    else if(strcmp(fun,"post_power")==0){
        sprintf(str,"{\"power\":%s}",param);
        xp_mqtt_post_property(&test,str);
    }
    else if(strcmp(fun,"set_start")==0){
        sprintf(str,"{\"start\":%s}",param);
        xp_mqtt_post_property(&test,str);
    }
    else  if(strcmp(fun,"init")==0){
        xp_mqtt_test();
        aos_task_new("mqtt loop thread",xp_mqtt_loop_thread,&test,1024*2);
    }
    else if(strcmp(fun,"device_name")==0){
        aos_kv_set("device_name",param,strlen(param),1);
        println("device_name set as:%s",param);
    }
    else if(strcmp(fun,"device_secret")==0){
        aos_kv_set("device_secret",param,strlen(param),1);
        println("device_secret set as:%s",param);
    }
    else if(strcmp(fun,"product_key")==0){
        aos_kv_set("product_key",param,strlen(param),1);
        println("product_key set as:%s",param);
    }
    else if(strcmp(fun,"product_secret")==0){
        aos_kv_set("product_secret",param,strlen(param),1);
        println("product_secret set as:%s",param);
    }
    else{
        return 0;
    }
    return 1;
}
//end of the file
